package org.apache.ocean.main.search;

import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.ocean.ConstantScorePrefixQuery;
import org.apache.ocean.main.IndexSchema;
import org.apache.ocean.main.Snapshot;
import org.apache.ocean.main.fields.FieldType;
import org.apache.ocean.main.util.Range;
import org.apache.ocean.main.util.Timeout;

/**
 * 
 * @author jasonr
 */
// TODO: unit test OceanQueryParser
public class OceanQueryParser extends QueryParser {
	private IndexSchema.Category schemaCategory;
	private Snapshot snapshot;
	private Timeout timeout;

	public OceanQueryParser(String defaultFieldName, IndexSchema.Category schemaCategory, Snapshot snapshot, Timeout timeout) {
		super(defaultFieldName == null ? defaultFieldName : schemaCategory.getDefaultSearchFieldName(), schemaCategory.getQueryAnalyzer());
		this.schemaCategory = schemaCategory;
		this.timeout = timeout;
		setLowercaseExpandedTerms(false);
	}

	public static Query parse(String queryString, IndexSchema.Category schemaCategory) throws ParseException {
		return new OceanQueryParser(schemaCategory.getDefaultSearchFieldName(), schemaCategory, null, null).parse(queryString);
	}

	public static Query parse(String queryString, Snapshot snapshot, Timeout timeout) throws ParseException {
		return new OceanQueryParser(snapshot.getIndexSchemaCategory().getDefaultSearchFieldName(), snapshot.getIndexSchemaCategory(), snapshot, timeout).parse(queryString);
	}

	protected Query getFieldQuery(String field, String queryText) throws ParseException {
		return super.getFieldQuery(field, queryText);
	}

	protected Query getPrefixQuery(String field, String termStr) throws ParseException {
		if (getLowercaseExpandedTerms()) {
			termStr = termStr.toLowerCase();
		}
		Term term = new Term(field, termStr);
		return new ConstantScorePrefixQuery(term);
	}

	protected Query getRangeQuery(String field, String part1, String part2, boolean inclusive) throws ParseException {
		FieldType fieldType = schemaCategory.getField(field).getFieldType();
		Object object1 = null;
		Object object2 = null;
		try {
			if (!part1.equals("*")) {
				object1 = fieldType.stringToObject(part1);
			}
			if (!part2.equals("*")) {
				object2 = fieldType.stringToObject(part2);
			}
		} catch (Exception exception) {
      throw new ParseException(exception.getMessage());
		}
		if (object1 == null && object2 == null) {
			return new MatchAllDocsQuery();
		}
		// TODO: include type in range
		Range range = new Range(object1, inclusive, object2, inclusive);
		return new ConstantScoreRangeQuery(field, range, snapshot, timeout);
	}
}
